﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using WPNextTools.NBase;
using WPNextTools.NCommon;

namespace WPNextTools.NControls
{
    internal class VirtualizationStrategy
    {
        #region Fields
        internal PhotoListBox owner;
        internal double columnMarginCache;
        internal int columnCountCache;
        internal double[] columnY;
        internal Orientation orientationCache;
        internal double containerWidthCache;
        internal double leftRightMarginCache;
        private bool changeProperty = false;//Judge has propertyChagned,if has one changed call strategypropertychange method.
        #endregion

        #region Properties
        public Orientation Orientation
        {
            get { return orientationCache; }
            set
            {
                if (value != orientationCache)
                {
                    orientationCache = value;
                    this.OnOrientationChanged(value);
                }
            }
        }

        public int ColumnCount
        {
            get { return columnCountCache; }
            set
            {
                if (value != columnCountCache)
                {
                    columnCountCache = value;
                    this.OnColumCountCacheChanged(value);
                }
            }
        }


        public double ColumnMargin
        {
            get { return columnMarginCache; }
            set
            {
                if (value != columnMarginCache)
                {
                    columnMarginCache = value;
                    this.OnColumnMarginChanged(value);
                }
            }
        }

        public double LeftRightMargin
        {
            get { return leftRightMarginCache; }
            set
            {
                if (value != leftRightMarginCache)
                {
                    leftRightMarginCache = value;
                    this.OnLeftRightMarginChanged(value);
                }
            }
        }

        #endregion

        #region Changed
        internal virtual void OnColumCountCacheChanged(int columnCount)
        {
            columnY = new double[columnCount];
            changeProperty = true;
        }

        internal virtual void OnColumnMarginChanged(double columnMargin)
        {
            columnY = new double[columnCountCache];
            changeProperty = true;
        }

        internal virtual void OnOrientationChanged(Orientation newOrientation)
        {
            columnY = new double[columnCountCache];
            changeProperty = true;
        }

        internal virtual void OnContainerWidthChangd(double newContainerWidth)
        {
            columnY = new double[columnCountCache];
            changeProperty = true;
        }

        internal virtual void OnLeftRightMarginChanged(double leftRightMargin)
        {
            columnY = new double[columnCountCache];
            changeProperty = true;
        }

        internal virtual void OnStrategyPropertyChanged()
        {
            if (changeProperty && this.owner.listSource.Count > 0)
            {
                this.owner.realizedItems.Clear();//clear the show items container
                this.owner.itemsPanel.Children.Clear();//clear the PhotoListBoxItem that showed
                IDataSourceItem currentItem = this.owner.listSource.ListSourceItems[0];
                while (currentItem != null)
                {
                    //reset the IsShowed value , in ReCaculateContainer its will reget container.
                    currentItem.IsShowed = false;
                    //ReCaculate ItemPostion and Size
                    CaculateItemParams(currentItem);
                    currentItem = currentItem.Next;
                }
                if (this.owner.manipulationContainer.VerticalOffset == 0.0)
                {
                    this.owner.BalanceVisualSpace(0.0);
                }
                else
                {
                    this.owner.manipulationContainer.ScrollToVerticalOffset(0.0);
                }
                //recaculate itemcontainer size.
                AsyncContainerSize();
            }
        }
        #endregion
      
        #region owner

        internal virtual void ResetOwner()
        {
            this.owner = null;
        }

        internal virtual void InitializeOwner(PhotoListBox owner)
        {
            this.owner = owner;
        }

        #endregion

        #region ItemOperationRegion

        #region ItemAdded
        internal void RefreshViewportOnItemAdded(IDataSourceItem addedItem)
        {
            int index = addedItem.Index;
            if (index == 0 && this.owner.realizedItems.Count - 1 > 0)
            {
                this.OnItemAddedToTop(addedItem);
            }
            else
            {
                OnItemAdded(addedItem);
            }
            AsyncContainerSize();
        }

        internal void OnItemAddedToTop(IDataSourceItem dataSourceItem)
        {
            if (columnY != null)
            {
                columnY = new double[columnCountCache];
            }
            IDataSourceItem currentItem = dataSourceItem;
            while (currentItem != null)
            {
                bool showFlag = this.CaculateItemParams(currentItem);
                PhotoListBoxItem container = this.owner.GetRealizedContainerByItem(currentItem);
                if (showFlag)
                {
                    if (currentItem.IsShowed)
                    {
                        this.owner.RealizedOldContainer(container);
                    }
                    else
                    {
                        this.owner.RealizedNewContainer(currentItem);
                    }
                }
                else
                {
                    if (currentItem.IsShowed)
                    {
                        this.owner.RecoveryContainer(container);
                    }

                }
                currentItem = currentItem.Next;
            }
        }

        private void OnItemAdded(IDataSourceItem addedItem)
        {
            bool showFlag = this.CaculateItemParams(addedItem);
            if (showFlag)
            {
                //如果显示制造container
                this.owner.RealizedNewContainer(addedItem);
            }
        }

        #endregion

        #region ItemRemoved
        internal void RefreshViewportOnItemRemoved(IDataSourceItem dataSourceItem,int removeIndex)
        {
            //删除(回收)不现实的Container
            PhotoListBoxItem removeContainer = this.owner.GetRealizedContainerByItem(dataSourceItem);
            if (removeContainer != null)
            {
                this.owner.RecoveryContainer(removeContainer);
            }
            //获取开始改变位置的Item
            IDataSourceItem currentItem = this.owner.GetDataSourceItemByIndex(removeIndex);
            if (currentItem == null)
            {
                return;
            }
            //重置每列的高度
            if (columnY != null)
            {
                columnY = new double[columnCountCache];
            }
            List<int> columnTag = new List<int>();
            IDataSourceItem previousItem = currentItem.Previous;
            while (previousItem != null && columnTag.Count < columnCountCache)
            {
                int previousColumnIndex = previousItem.ColumnIndex;
                if (!columnTag.Contains(previousColumnIndex))
                {
                    columnY[previousColumnIndex] = previousItem.Y + previousItem.Height;
                    columnTag.Add(previousColumnIndex);
                }
                previousItem = previousItem.Previous;
            }
            //重新计算每个元素的位置
            IDataSourceItem nextItem = currentItem;
            while (nextItem != null)
            {
                bool showFlag = CaculateItemParams(nextItem);//是否要显示
                //如果显示了的则只移动位置
                if (nextItem.IsShowed)
                {
                    PhotoListBoxItem container = this.owner.GetRealizedContainerByItem(nextItem);
                    this.owner.RealizedOldContainer(container);
                }
                //如果没有显示要显示的则制造新的Container并显示出来
                if (!nextItem.IsShowed && showFlag)
                {
                    this.owner.RealizedNewContainer(nextItem);
                }
                nextItem = nextItem.Next;
            }
            AsyncContainerSize();
        }
        #endregion

        #region ItemReplace
        internal void RefreshViewportOnItemReplaced(IDataSourceItem iDataSourceItem)
        {
            
        }
        #endregion

        #region ItemReset
        internal void RefreshViewportOnItemReset()
        {
            //1.realizeditems
            this.owner.ClearResource();
            //2.重置每列高度
            if (columnY != null)
            {
                columnY = new double[columnCountCache];
            }
        }
        #endregion

        #endregion

        #region VirtualizationRegion

        #region VirtualizingContainer
        internal void ReCaculateContainer(double offset)
        {
            IDataSourceItem topVisibleItem = this.owner.GetTopVisibleItem(offset);
            IDataSourceItem bottomVisibleItem = this.owner.GetBottomVisibleItem(offset);

            int firstIndex = topVisibleItem.Index;
            int lastIndex = bottomVisibleItem.Index;

            //Debug.WriteLine("显示的第一个元素的索引-->" + firstIndex + "显示的最后一个元素的索引:" + lastIndex);

            //处理应该显示的
            IDataSourceItem currentItem = topVisibleItem;
            while (true)
            {
                if (!currentItem.IsShowed)
                {
                    this.owner.RealizedNewContainer(currentItem);
                    //Debug.WriteLine("重新加载-->");
                }
                if (currentItem == bottomVisibleItem)
                {
                    break;
                }
                currentItem = currentItem.Next;
            }

            //处理应该隐藏掉的
            for (int i = 0; i < this.owner.realizedItems.Count; i++)
            {
                PhotoListBoxItem container = this.owner.realizedItems[i];
                if (container.associatedDataItem.Index < firstIndex || container.associatedDataItem.Index > lastIndex)
                {
                    //Debug.WriteLine("清除加载-->");
                    this.owner.RecoveryContainer(container);
                }
            }
        }
        #endregion

        #region Async
        protected virtual void AsyncContainerSize()
        {
            this.owner.ChangePanelHeight(GetMaxColumnHeight());
        }

        #endregion

        #endregion

        #region PhotoPositionCaculate

        #region CaculatePosition

        /// <summary>
        /// 给获取的container 重置位置
        /// </summary>
        /// <param name="itemRealizedIndexFromListSourceIndex"></param>
        /// <param name="containerForItem"></param>
        protected virtual bool CaculateItemParams(IDataSourceItem dataSourceItem)
        {
            int lowestIndex = GetLowestIndex();
            double imgRatio = 1.0;
            if (dataSourceItem.Value is IImageModel)
            {
                imgRatio = ((IImageModel)dataSourceItem.Value).ImgRatio;
            }
            else
            {
                PropertyInfo property = dataSourceItem.Value.GetType().GetProperty("ImgRatio");
                if (property != null && property.CanRead)
                {
                    imgRatio = (double)property.GetValue(dataSourceItem.Value);
                }
                else
                {
                    throw new InvalidOperationException("It's no implements IImageModel!");
                }
            }

            double width = GetColumnWidth();
            double height = width * imgRatio;
            double x = (columnMarginCache + width) * lowestIndex;
            //Debug.WriteLine("columnMargin:" + columnMarginCache);
            double y = columnY[lowestIndex] + columnMarginCache;

            if (columnY[lowestIndex] == 0.0)
            {
                y = 0.0;
            }

            dataSourceItem.Width = width;
            dataSourceItem.Height = height;
            dataSourceItem.X = x;
            dataSourceItem.Y = this.owner.NeedCorrect ? y - 4 : y;
            dataSourceItem.ColumnIndex = lowestIndex;
            columnY[lowestIndex] = y + height;

            double virtualY = y - this.owner.manipulationContainer.VerticalOffset;
            if (virtualY >= -NEnviroment.ScrreenHeight && virtualY <= NEnviroment.ScrreenHeight * 2)
            {
                return true;
            }
            return false;
        }
        #endregion

        internal void OnViewportSizeChanged(Size newSize, Size oldSize)
        {
            this.containerWidthCache = newSize.Width;
        }

        protected virtual double GetColumnWidth()
        {
            containerWidthCache = NEnviroment.ScreenWidth - 2 * leftRightMarginCache;
            double averageWidth = (containerWidthCache - (columnCountCache - 1) * columnMarginCache) / columnCountCache;
            return averageWidth;
        }

        protected virtual double GetMaxColumnHeight()
        {
            int index = 0;
            for (int i = 1; i < columnCountCache; i++)
            {
                if (columnY[index] < columnY[i])
                {
                    index = i;
                }
            }
            return columnY[index];
        }

        /// <summary>
        /// 获取高度最低的列
        /// </summary>
        /// <returns></returns>
        protected virtual int GetLowestIndex()
        {
            int index = 0;
            for (int i = 1; i < columnCountCache; i++)
            {
                if (columnY[index] > columnY[i])
                {
                    index = i;
                }
            }
            return index;
        }
        #endregion

        #region ScrollbarVisibility

        internal void UpdateScrollBarVisibility()
        {
            if (Orientation == null || Orientation == Orientation.Vertical)
            {
                this.owner.manipulationContainer.VerticalScrollBarVisibility = this.owner.verticalScrollBarVisibilityCache;
            }
            else
            {
                this.owner.manipulationContainer.HorizontalScrollBarVisibility = this.owner.horizontalScrollBarVisibilityCache;
            }
        }
        #endregion

        
    }
}
